#include "printf.h"
#include "console.h"
#include <stdarg.h>
#include <stdint.h>

/* 缓冲区字符写入辅助函数 */
static inline int buf_putc(char **pp, char *end, char c) {
    if (*pp < end) {
        *(*pp)++ = c;
        return 1;
    }
    return 0; /* 缓冲区已满 */
}

/* 无符号数字转换到缓冲区 */
static int utoa_to_buf(unsigned long long v, int base, int uppercase, char **pp, char *end) {
    char tmp[65]; int ti = 0;
    const char *digits_l = "0123456789abcdef";
    const char *digits_U = "0123456789ABCDEF";
    const char *digits = uppercase ? digits_U : digits_l;
    if (v == 0) tmp[ti++] = '0';
    while (v) {
        tmp[ti++] = digits[v % base];
        v /= base;
    }
    int written = 0;
    while (ti--) {  /* 反向输出 */
        if (!buf_putc(pp, end, tmp[ti])) break;
        written++;
    }
    return written;
}

/* 有符号数字转换到缓冲区 */
static int itoa_signed_to_buf(long long val, int base, int uppercase, char **pp, char *end) {
    if (val < 0) { /* 处理负数：先输出负号，再转换正值 */
        unsigned long long ux = (unsigned long long)(- (long long) val);
        buf_putc(pp, end, '-');
        return 1 + utoa_to_buf(ux, base, uppercase, pp, end);
    }
    return utoa_to_buf((unsigned long long)val, base, uppercase, pp, end);
}

/* 可变参数格式化字符串处理 */
/* vsnprintf: supports %d %u %x %X %p %s %c %% */
int vsnprintf(char *buf, int size, const char *fmt, va_list ap) {
    char *p = buf;
    char *end = buf + (size > 0 ? size - 1 : 0);
    const char *s = fmt;
    while (*s) {
        if (*s != '%') {
            if (!buf_putc(&p, end, *s++)) break;
            continue;
        }
        s++; // skip '%'
        if (*s == '%') { buf_putc(&p, end, '%'); s++; continue; }

        int longflag = 0;
        if (*s == 'l') { // handle 'l', 'll'
            longflag++;
            s++;
            if (*s == 'l') { longflag++; s++; }
        }

        char spec = *s++;
        switch (spec) {
        case 'd':
        case 'i': {
            long long v = longflag ? va_arg(ap, long long) : va_arg(ap, int);
            itoa_signed_to_buf(v, 10, 0, &p, end);
            break;
        }
        case 'u': {
            unsigned long long v = longflag ? va_arg(ap, unsigned long long)
                                            : va_arg(ap, unsigned int);
            utoa_to_buf(v, 10, 0, &p, end);
            break;
        }
        case 'x':
        case 'X': {
            unsigned long long v = longflag ? va_arg(ap, unsigned long long)
                                            : va_arg(ap, unsigned int);
            utoa_to_buf(v, 16, (spec == 'X'), &p, end);
            break;
        }
        case 'p': {
            void *pv = va_arg(ap, void*);
            unsigned long long v = (unsigned long long)(uintptr_t)pv;
            buf_putc(&p, end, '0');
            buf_putc(&p, end, 'x');
            utoa_to_buf(v, 16, 0, &p, end);
            break;
        }
        case 's': {
            const char *str = va_arg(ap, const char*);
            if (!str) str = "(null)";
            while (*str && p < end) buf_putc(&p, end, *str++);
            break;
        }
        case 'c': {
            int c = va_arg(ap, int);
            buf_putc(&p, end, (char)c);
            break;
        }
        default:
            buf_putc(&p, end, '%');
            if (spec) buf_putc(&p, end, spec);
            break;
        }
    }
    if (size > 0) *p = '\0';
    return (int)(p - buf);
}

/* 包装函数：snprintf */
int snprintf(char *buf, int size, const char *fmt, ...) {
    va_list ap; va_start(ap, fmt);
    int r = vsnprintf(buf, size, fmt, ap);
    va_end(ap);
    return r;
}

/* 内核格式化输出函数 */
#define CONSOLE_TMPBUF 512
int cprintf(const char *fmt, ...) {
    char tmp[CONSOLE_TMPBUF];
    va_list ap; va_start(ap, fmt);
    int n = vsnprintf(tmp, sizeof(tmp), fmt, ap);
    va_end(ap);
    console_puts(tmp);
    return n;
}

/* 带颜色输出的格式化函数 */
int cprintf_color(int fg_color, const char *fmt, ...) {
    char tmp[CONSOLE_TMPBUF];
    va_list ap; va_start(ap, fmt);
    int n = vsnprintf(tmp, sizeof(tmp), fmt, ap);
    va_end(ap);

    if (fg_color >= 30 && fg_color <= 37) {
        /* 添加ANSI颜色序列 */
        char out[CONSOLE_TMPBUF + 32];
        int len = snprintf(out, sizeof(out), "\x1b[%dm%s\x1b[0m", fg_color, tmp);
        (void)len;
        console_puts(out);
    } else {
        console_puts(tmp);
    }
    return n;
}
